// eq_util.js
const F_MAX = 20000.0;
const F_MIN = 20.0;
const F = 48000.0;
const R = 2 * Math.PI;

class EQUtil {
    /// 将自然对数转换成以 10 为底的对数a
    static _log10(x) {
        return Math.log(x) / Math.log(10);
    }

    /**
     * 把频率值映射到线性范围内
     * @param {number} frency - 频率
     * @param {number} width - 线性范围
     * @returns {number}
     */
    static toInt(frency, width) {
        const f = EQUtil._log10(22000.0) - EQUtil._log10(20.0);
        const f1 = EQUtil._log10(frency) - EQUtil._log10(20.0);
        return (f1 / f) * width;
    }

    /**
     * 把线性范围值映射回频率
     * @param {number} v
     * @param {number} v_max 横向的最大像素点，一般是折线图的宽度，也就是maxwidth
     * @param {number} v_min 横向的最小的像素点，一般是折线图的起点，也就是0
     * @param {object} [options]
     * @param {number} [options.f_max=22000]
     * @returns {number}
     */
    static deInt(v, v_max, v_min, options = {}) {
        const f_max = options.f_max || 22000.0;
        const s_v = (v - v_min) / (v_max - v_min);
        const f = EQUtil._log10(f_max) - EQUtil._log10(20.0);
        const result = Math.pow(10.0, s_v * f + EQUtil._log10(20.0));
        return result;
    }

    /**
     * PEQ特性点增益值算法
     * @param {number} quality
     * @param {number} gain
     * @param {number} frency
     * @param {number[]} array
     */
    static eq(quality, gain, frency, array) {
        const var0 = Math.pow(10.0, gain / 40.0);
        const var1 = R * frency / F;
        const var2 = Math.sin(var1) / (2 * quality);
        const var3 = var2 / var0;
        const var4 = -2.0 * Math.cos(var1);
        const var5 = 1.0 - var2 / var0;
        const var6 = -2.0 * Math.cos(var1);
        const var7 = (1.0 - var2 * var0) * 1.0;
        const negVar6 = -var6;
        const negVar4 = -var4;

        for (let i = 0; i < array.length; i++) {
            const f = EQUtil.deInt(i, array.length, 0);
            const var10 = R * f / F;
            const cosVar10 = Math.cos(var10);
            const cos2Var10 = Math.cos(2.0 * var10);
            const sinVar10 = Math.sin(var10);
            const sin2Var10 = Math.sin(2.0 * var10);

            const term1 = cosVar10 * var6 + (1.0 + var2 * var0) * 1.0 + cos2Var10 * var7;
            const term2 = negVar6 * sinVar10 - sin2Var10 * var7;
            const term3 = cosVar10 * var4 + 1.0 + var3 + cos2Var10 * var5;
            const term4 = negVar4 * sinVar10 - sin2Var10 * var5;

            const numerator = Math.pow(term1, 2.0) + Math.pow(term2, 2.0);
            const denominator = Math.pow(term3, 2.0) + Math.pow(term4, 2.0);

            const sqrtValue = Math.sqrt(numerator / denominator);
            array[i] = EQUtil._log10(sqrtValue);
        }
    }

    /**
     * 计算滤波器的相位响应或幅值响应
     * @param {number[]} a
     * @param {number[]} b
     * @param {number[]} one
     * @param {boolean} ispol
     */
    static _mk(a, b, one, ispol) {
        const len = one.length;
        let x, w, u, v, s, t, h;

        for (let i = 0; i < len; i++) {
            x = EQUtil.deInt(i, len, 0, { f_max: F_MAX });
            w = 2 * Math.PI * x / F;

            u = b[0] + b[1] * Math.cos(w) + b[2] * Math.cos(2 * w);
            v = -b[1] * Math.sin(w) - b[2] * Math.sin(2 * w);

            s = a[0] + a[1] * Math.cos(w) + a[2] * Math.cos(2 * w);
            t = -a[1] * Math.sin(w) - a[2] * Math.sin(2 * w);

            if (ispol) {
                const Im = (s * v - t * u);
                const Re = (s * u + t * v);
                h = 180 * Math.atan2(Im, Re) / Math.PI;
            } else {
                h = Math.sqrt((u ** 2 + v ** 2) / (s ** 2 + t ** 2));
                h = EQUtil._log10(h);
            }

            one[i] = h;
        }
    }

    /**
     * 创建包含指定数量零的数组
     * @param {number} count
     * @returns {number[]}
     */
    static _getArray(count) {
        return new Array(count).fill(0.0);
    }


    static filter(f, octType, ishpass, bypass, array) {
        let p = this._getArray(4);
        let a0 = this._getArray(3);
        let a1 = this._getArray(3);
        let a2 = this._getArray(3);
        let a3 = this._getArray(3);
        let b0 = this._getArray(3);
        let b1 = this._getArray(3);
        let b2 = this._getArray(3);
        let b3 = this._getArray(3);

        let one_0 = this._getArray(array.length);
        let one_1 = this._getArray(array.length);
        let one_2 = this._getArray(array.length);
        let one_3 = this._getArray(array.length);

        // Calculate angular frequency
        let w0 = 2 * Math.PI * f / F;
        let oc = 2 * Math.tan(w0 / 2);
        let c1 = oc * Math.tan(w0 / 2);

        let iszero = (f === F_MAX && !ishpass) || (f === F_MIN && ishpass) || bypass;
        if (iszero) {
            array.fill(0);
            return array;
        }
        switch (octType) {
            case 0: // BW-06
                p[0] = ishpass ? 1 : 0;

                a0[0] = ishpass ? 1 : 1;
                a0[1] = ishpass ? ((c1 - p[0] * oc) / (c1 + p[0] * oc)) : (oc - 2) / (oc + 2);
                a0[2] = ishpass ? 0 : 0;

                b0[0] = ishpass ? (oc / (c1 + p[0] * oc)) : oc / (2 + oc);
                b0[1] = ishpass ? -b0[0] : b0[0];
                b0[2] = ishpass ? 0 : 0;

                this._mk(a0, b0, one_0, false);
                array = iszero ? this._getArray(array.length) : one_0;
                break;

            case 1: // BW-12
                p[0] = ishpass ? 1.41421356237309 : 1.41421356237309;

                a0[0] = ishpass ? 1 : 1;
                a0[1] = ishpass
                    ? (-2 * (oc * oc - c1 * c1) / (c1 * c1 + c1 * p[0] * oc + oc * oc))
                    : 2 * (oc * oc - 4) / (4 + 2 * p[0] * oc + oc * oc);
                a0[2] = ishpass
                    ? ((c1 * c1 - c1 * p[0] * oc + oc * oc) / (c1 * c1 + c1 * p[0] * oc + oc * oc))
                    : (4 - 2 * p[0] * oc + oc * oc) / (4 + 2 * p[0] * oc + oc * oc);

                b0[0] = ishpass ? (oc * oc / (c1 * c1 + c1 * p[0] * oc + oc * oc)) : oc * oc / (4 + 2 * p[0] * oc + oc * oc);
                b0[1] = ishpass ? -2 * b0[0] : 2 * b0[0];
                b0[2] = ishpass ? b0[0] : b0[0];

                this._mk(a0, b0, one_0, false);
                array = iszero ? this._getArray(array.length) : one_0;
                break;
            case 2: // BW-18
                p[0] = ishpass ? 1 : 1;
                p[1] = ishpass ? 1 : 1;

                a0[0] = ishpass ? 1 : 1;
                a0[1] = ishpass
                    ? (-2 * (oc * oc - c1 * c1) / (c1 * c1 + c1 * p[0] * oc + oc * oc))
                    : (2 * (oc * oc - 4) / (4 + 2 * p[0] * oc + oc * oc));
                a0[2] = ishpass
                    ? ((c1 * c1 - c1 * p[0] * oc + oc * oc) / (c1 * c1 + c1 * p[0] * oc + oc * oc))
                    : ((4 - 2 * p[0] * oc + oc * oc) / (4 + 2 * p[0] * oc + oc * oc));

                a1[0] = ishpass ? 1 : 1;
                a1[1] = ishpass ? (-(p[1] * oc - c1) / (c1 + p[1] * oc)) : ((p[1] * oc - 2) / (2 + p[1] * oc));
                a1[2] = ishpass ? 0 : 0;

                b0[0] = ishpass ? (oc * oc / (c1 * c1 + c1 * p[0] * oc + oc * oc)) : (oc * oc / (4 + 2 * p[0] * oc + oc * oc));
                b0[1] = ishpass ? -2 * b0[0] : (2 * b0[0]);
                b0[2] = ishpass ? b0[0] : b0[0];

                b1[0] = ishpass ? (p[1] * oc / (c1 + p[1] * oc)) : (p[1] * oc / (2 + p[1] * oc));
                b1[1] = ishpass ? -b1[0] : b1[0];
                b1[2] = ishpass ? 0 : 0;

                this._mk(a0, b0, one_0, false);
                this._mk(a1, b1, one_1, false);
                array = iszero ? this._getArray(array.length) : array.map((_, i) => one_0[i] + one_1[i]);
                break;

            case 3: // BW-24
                p[0] = ishpass ? 0.76536686473018 : 0.76536686473018;
                p[1] = ishpass ? 1.84775906502257 : 1.84775906502257;

                a0[0] = ishpass ? 1 : 1;
                a0[1] = ishpass
                    ? (-2 * (oc * oc - c1 * c1) / (c1 * c1 + c1 * p[0] * oc + oc * oc))
                    : (2 * (oc * oc - 4) / (4 + 2 * p[0] * oc + oc * oc));
                a0[2] = ishpass
                    ? ((c1 * c1 - c1 * p[0] * oc + oc * oc) / (c1 * c1 + c1 * p[0] * oc + oc * oc))
                    : ((4 - 2 * p[0] * oc + oc * oc) / (4 + 2 * p[0] * oc + oc * oc));

                a1[0] = ishpass ? 1 : 1;
                a1[1] = ishpass
                    ? (-2 * (oc * oc - c1 * c1) / (c1 * c1 + c1 * p[1] * oc + oc * oc))
                    : (2 * (oc * oc - 4) / (4 + 2 * p[1] * oc + oc * oc));
                a1[2] = ishpass
                    ? ((c1 * c1 - c1 * p[1] * oc + oc * oc) / (c1 * c1 + c1 * p[1] * oc + oc * oc))
                    : ((4 - 2 * p[1] * oc + oc * oc) / (4 + 2 * p[1] * oc + oc * oc));

                b0[0] = ishpass ? (oc * oc / (c1 * c1 + c1 * p[0] * oc + oc * oc)) : (oc * oc / (4 + 2 * p[0] * oc + oc * oc));
                b0[1] = ishpass ? (-2 * b0[0]) : (2 * b0[0]);
                b0[2] = ishpass ? b0[0] : b0[0];

                b1[0] = ishpass ? (oc * oc / (c1 * c1 + c1 * p[1] * oc + oc * oc)) : (oc * oc / (4 + 2 * p[1] * oc + oc * oc));
                b1[1] = ishpass ? (-2 * b1[0]) : (2 * b1[0]);
                b1[2] = ishpass ? b1[0] : b1[0];

                this._mk(a0, b0, one_0, false);
                this._mk(a1, b1, one_1, false);
                array = iszero ? this._getArray(array.length) : array.map((_, i) => one_0[i] + one_1[i]);
                break;

            case 4: // BW-36
                p[0] = ishpass ? 0.51763809020504 : 0.51763809020504;
                p[1] = ishpass ? 1.41421356237309 : 1.41421356237309;
                p[2] = ishpass ? 1.93185165257814 : 1.93185165257814;

                a0[0] = ishpass ? 1 : 1;
                a0[1] = ishpass
                    ? (-2 * (oc * oc - c1 * c1) / (c1 * c1 + c1 * p[0] * oc + oc * oc))
                    : (2 * (oc * oc - 4) / (4 + 2 * p[0] * oc + oc * oc));
                a0[2] = ishpass
                    ? ((c1 * c1 - c1 * p[0] * oc + oc * oc) / (c1 * c1 + c1 * p[0] * oc + oc * oc))
                    : ((4 - 2 * p[0] * oc + oc * oc) / (4 + 2 * p[0] * oc + oc * oc));

                a1[0] = ishpass ? 1 : 1;
                a1[1] = ishpass
                    ? (-2 * (oc * oc - c1 * c1) / (c1 * c1 + c1 * p[1] * oc + oc * oc))
                    : (2 * (oc * oc - 4) / (4 + 2 * p[1] * oc + oc * oc));
                a1[2] = ishpass
                    ? ((c1 * c1 - c1 * p[1] * oc + oc * oc) / (c1 * c1 + c1 * p[1] * oc + oc * oc))
                    : ((4 - 2 * p[1] * oc + oc * oc) / (4 + 2 * p[1] * oc + oc * oc));

                a2[0] = ishpass ? 1 : 1;
                a2[1] = ishpass
                    ? (-2 * (oc * oc - c1 * c1) / (c1 * c1 + c1 * p[2] * oc + oc * oc))
                    : (2 * (oc * oc - 4) / (4 + 2 * p[2] * oc + oc * oc));
                a2[2] = ishpass
                    ? ((c1 * c1 - c1 * p[2] * oc + oc * oc) / (c1 * c1 + c1 * p[2] * oc + oc * oc))
                    : ((4 - 2 * p[2] * oc + oc * oc) / (4 + 2 * p[2] * oc + oc * oc));

                b0[0] = ishpass ? (oc * oc / (c1 * c1 + c1 * p[0] * oc + oc * oc)) : (oc * oc / (4 + 2 * p[0] * oc + oc * oc));
                b0[1] = ishpass ? (-2 * b0[0]) : (2 * b0[0]);
                b0[2] = ishpass ? b0[0] : b0[0];

                b1[0] = ishpass ? (oc * oc / (c1 * c1 + c1 * p[1] * oc + oc * oc)) : (oc * oc / (4 + 2 * p[1] * oc + oc * oc));
                b1[1] = ishpass ? (-2 * b1[0]) : (2 * b1[0]);
                b1[2] = ishpass ? b1[0] : b1[0];

                b2[0] = ishpass ? (oc * oc / (c1 * c1 + c1 * p[2] * oc + oc * oc)) : (oc * oc / (4 + 2 * p[2] * oc + oc * oc));
                b2[1] = ishpass ? (-2 * b2[0]) : (2 * b2[0]);
                b2[2] = ishpass ? b2[0] : b2[0];

                this._mk(a0, b0, one_0, false);
                this._mk(a1, b1, one_1, false);
                this._mk(a2, b2, one_2, false);
                array = iszero ? this._getArray(array.length) : array.map((_, i) => one_0[i] + one_1[i] + one_2[i]);
                break;

            case 5: // BW-48
                p[0] = ishpass ? 0.39018064403226 : 0.39018064403226;
                p[1] = ishpass ? 1.11114046603920 : 1.11114046603920;
                p[2] = ishpass ? 1.66293922460509 : 1.66293922460509;
                p[3] = ishpass ? 1.96157056080646 : 1.96157056080646;

                a0[0] = ishpass ? 1 : 1;
                a0[1] = ishpass
                    ? (-2 * (oc * oc - c1 * c1) / (c1 * c1 + c1 * p[0] * oc + oc * oc))
                    : (2 * (oc * oc - 4) / (4 + 2 * p[0] * oc + oc * oc));
                a0[2] = ishpass
                    ? ((c1 * c1 - c1 * p[0] * oc + oc * oc) / (c1 * c1 + c1 * p[0] * oc + oc * oc))
                    : ((4 - 2 * p[0] * oc + oc * oc) / (4 + 2 * p[0] * oc + oc * oc));

                a1[0] = ishpass ? 1 : 1;
                a1[1] = ishpass
                    ? (-2 * (oc * oc - c1 * c1) / (c1 * c1 + c1 * p[1] * oc + oc * oc))
                    : (2 * (oc * oc - 4) / (4 + 2 * p[1] * oc + oc * oc));
                a1[2] = ishpass
                    ? ((c1 * c1 - c1 * p[1] * oc + oc * oc) / (c1 * c1 + c1 * p[1] * oc + oc * oc))
                    : ((4 - 2 * p[1] * oc + oc * oc) / (4 + 2 * p[1] * oc + oc * oc));

                a2[0] = ishpass ? 1 : 1;
                a2[1] = ishpass
                    ? (-2 * (oc * oc - c1 * c1) / (c1 * c1 + c1 * p[2] * oc + oc * oc))
                    : (2 * (oc * oc - 4) / (4 + 2 * p[2] * oc + oc * oc));
                a2[2] = ishpass
                    ? ((c1 * c1 - c1 * p[2] * oc + oc * oc) / (c1 * c1 + c1 * p[2] * oc + oc * oc))
                    : ((4 - 2 * p[2] * oc + oc * oc) / (4 + 2 * p[2] * oc + oc * oc));

                a3[0] = ishpass ? 1 : 1;
                a3[1] = ishpass
                    ? (-2 * (oc * oc - c1 * c1) / (c1 * c1 + c1 * p[3] * oc + oc * oc))
                    : (2 * (oc * oc - 4) / (4 + 2 * p[3] * oc + oc * oc));
                a3[2] = ishpass
                    ? ((c1 * c1 - c1 * p[3] * oc + oc * oc) / (c1 * c1 + c1 * p[3] * oc + oc * oc))
                    : ((4 - 2 * p[3] * oc + oc * oc) / (4 + 2 * p[3] * oc + oc * oc));

                b0[0] = ishpass ? (oc * oc / (c1 * c1 + c1 * p[0] * oc + oc * oc)) : (oc * oc / (4 + 2 * p[0] * oc + oc * oc));
                b0[1] = ishpass ? (-2 * b0[0]) : (2 * b0[0]);
                b0[2] = ishpass ? b0[0] : b0[0];

                b1[0] = ishpass ? (oc * oc / (c1 * c1 + c1 * p[1] * oc + oc * oc)) : (oc * oc / (4 + 2 * p[1] * oc + oc * oc));
                b1[1] = ishpass ? (-2 * b1[0]) : (2 * b1[0]);
                b1[2] = ishpass ? b1[0] : b1[0];

                b2[0] = ishpass ? (oc * oc / (c1 * c1 + c1 * p[2] * oc + oc * oc)) : (oc * oc / (4 + 2 * p[2] * oc + oc * oc));
                b2[1] = ishpass ? (-2 * b2[0]) : (2 * b2[0]);
                b2[2] = ishpass ? b2[0] : b2[0];

                b3[0] = ishpass ? (oc * oc / (c1 * c1 + c1 * p[3] * oc + oc * oc)) : (oc * oc / (4 + 2 * p[3] * oc + oc * oc));
                b3[1] = ishpass ? (-2 * b3[0]) : (2 * b3[0]);
                b3[2] = ishpass ? b3[0] : b3[0];

                this._mk(a0, b0, one_0, false);
                this._mk(a1, b1, one_1, false);
                this._mk(a2, b2, one_2, false);
                this._mk(a3, b3, one_3, false);
                array = iszero ? this._getArray(array.length) : array.map((_, i) => one_0[i] + one_1[i] + one_2[i] + one_3[i]);
                break;

            case 6: // BS-12
                p[0] = ishpass ? 1.73205080756888 : 1.73205080756888;

                a0[0] = ishpass ? 1 : 1;
                a0[1] = ishpass
                    ? (-2 * (oc * oc - c1 * c1) / (c1 * c1 + c1 * p[0] * oc + oc * oc))
                    : (2 * (oc * oc - 4) / (4 + 2 * p[0] * oc + oc * oc));
                a0[2] = ishpass
                    ? ((c1 * c1 - c1 * p[0] * oc + oc * oc) / (c1 * c1 + c1 * p[0] * oc + oc * oc))
                    : ((4 - 2 * p[0] * oc + oc * oc) / (4 + 2 * p[0] * oc + oc * oc));

                b0[0] = ishpass ? (oc * oc / (c1 * c1 + c1 * p[0] * oc + oc * oc)) : (oc * oc / (4 + 2 * p[0] * oc + oc * oc));
                b0[1] = ishpass ? (-2 * b0[0]) : (2 * b0[0]);
                b0[2] = ishpass ? b0[0] : b0[0];

                one_0 = this._getArray(array.length);
                this._mk(a0, b0, one_0, false);
                array = iszero ? this._getArray(array.length) : one_0;
                break;
            case 7: // BS-18
                p[0] = ishpass ? 1.49128077169616 : 1.49128077169616;
                p[1] = ishpass ? 0.94160002653321 : 0.94160002653321;

                a0[0] = ishpass ? 1 : 1;
                a0[1] = ishpass
                    ? (-2 * (oc * oc - c1 * c1) / (c1 * c1 + c1 * p[0] * oc + oc * oc))
                    : (2 * (oc * oc - 4) / (4 + 2 * p[0] * oc + oc * oc));
                a0[2] = ishpass
                    ? ((c1 * c1 - c1 * p[0] * oc + oc * oc) / (c1 * c1 + c1 * p[0] * oc + oc * oc))
                    : ((4 - 2 * p[0] * oc + oc * oc) / (4 + 2 * p[0] * oc + oc * oc));

                a1[0] = ishpass ? 1 : 1;
                a1[1] = ishpass ? (-(p[1] * oc - c1) / (c1 + p[1] * oc)) : ((p[1] * oc - 2) / (2 + p[1] * oc));
                a1[2] = ishpass ? 0 : 0;

                b0[0] = ishpass ? (oc * oc / (c1 * c1 + c1 * p[0] * oc + oc * oc)) : (oc * oc / (4 + 2 * p[0] * oc + oc * oc));
                b0[1] = ishpass ? (-2 * b0[0]) : (2 * b0[0]);
                b0[2] = ishpass ? b0[0] : b0[0];

                b1[0] = ishpass ? (p[1] * oc / (c1 + p[1] * oc)) : (p[1] * oc / (2 + p[1] * oc));
                b1[1] = ishpass ? (-b1[0]) : b1[0];
                b1[2] = ishpass ? 0 : 0;

                this._mk(a0, b0, one_0, false);
                this._mk(a1, b1, one_1, false);
                array = iszero ? this._getArray(array.length) : array.map((_, i) => one_0[i] + one_1[i]);
                break;

            case 8: // BS-24
                p[0] = ishpass ? 1.31442234334377 : 1.31442234334377;
                p[1] = ishpass ? 1.80951759357649 : 1.80951759357649;

                a0[0] = ishpass ? 1 : 1;
                a0[1] = ishpass
                    ? (-2 * (oc * oc - c1 * c1) / (c1 * c1 + c1 * p[0] * oc + oc * oc))
                    : (2 * (oc * oc - 4) / (4 + 2 * p[0] * oc + oc * oc));
                a0[2] = ishpass
                    ? ((c1 * c1 - c1 * p[0] * oc + oc * oc) / (c1 * c1 + c1 * p[0] * oc + oc * oc))
                    : ((4 - 2 * p[0] * oc + oc * oc) / (4 + 2 * p[0] * oc + oc * oc));

                a1[0] = ishpass ? 1 : 1;
                a1[1] = ishpass
                    ? (-2 * (oc * oc - c1 * c1) / (c1 * c1 + c1 * p[1] * oc + oc * oc))
                    : (2 * (oc * oc - 4) / (4 + 2 * p[1] * oc + oc * oc));
                a1[2] = ishpass
                    ? ((c1 * c1 - c1 * p[1] * oc + oc * oc) / (c1 * c1 + c1 * p[1] * oc + oc * oc))
                    : ((4 - 2 * p[1] * oc + oc * oc) / (4 + 2 * p[1] * oc + oc * oc));

                b0[0] = ishpass ? (oc * oc / (c1 * c1 + c1 * p[0] * oc + oc * oc)) : (oc * oc / (4 + 2 * p[0] * oc + oc * oc));
                b0[1] = ishpass ? (-2 * b0[0]) : (2 * b0[0]);
                b0[2] = ishpass ? b0[0] : b0[0];

                b1[0] = ishpass ? (oc * oc / (c1 * c1 + c1 * p[1] * oc + oc * oc)) : (oc * oc / (4 + 2 * p[1] * oc + oc * oc));
                b1[1] = ishpass ? (-2 * b1[0]) : (2 * b1[0]);
                b1[2] = ishpass ? b1[0] : b1[0];

                this._mk(a0, b0, one_0, false);
                this._mk(a1, b1, one_1, false);
                array = iszero ? this._getArray(array.length) : array.map((_, i) => one_0[i] + one_1[i]);
                break;
            case 9: // BS-36
                p[0] = ishpass ? 1.81878136609445 : 1.81878136609445;
                p[1] = ishpass ? 1.59930837166566 : 1.59930837166566;
                p[2] = ishpass ? 1.07710536333862 : 1.07710536333862;

                a0[0] = ishpass ? 1 : 1;
                a0[1] = ishpass
                    ? (-2 * (oc * oc - c1 * c1) / (c1 * c1 + c1 * p[0] * oc + oc * oc))
                    : (2 * (oc * oc - 4) / (4 + 2 * p[0] * oc + oc * oc));
                a0[2] = ishpass
                    ? ((c1 * c1 - c1 * p[0] * oc + oc * oc) / (c1 * c1 + c1 * p[0] * oc + oc * oc))
                    : ((4 - 2 * p[0] * oc + oc * oc) / (4 + 2 * p[0] * oc + oc * oc));

                a1[0] = ishpass ? 1 : 1;
                a1[1] = ishpass
                    ? (-2 * (oc * oc - c1 * c1) / (c1 * c1 + c1 * p[1] * oc + oc * oc))
                    : (2 * (oc * oc - 4) / (4 + 2 * p[1] * oc + oc * oc));
                a1[2] = ishpass
                    ? ((c1 * c1 - c1 * p[1] * oc + oc * oc) / (c1 * c1 + c1 * p[1] * oc + oc * oc))
                    : ((4 - 2 * p[1] * oc + oc * oc) / (4 + 2 * p[1] * oc + oc * oc));

                a2[0] = ishpass ? 1 : 1;
                a2[1] = ishpass
                    ? (-2 * (oc * oc - c1 * c1) / (c1 * c1 + c1 * p[2] * oc + oc * oc))
                    : (2 * (oc * oc - 4) / (4 + 2 * p[2] * oc + oc * oc));
                a2[2] = ishpass
                    ? ((c1 * c1 - c1 * p[2] * oc + oc * oc) / (c1 * c1 + c1 * p[2] * oc + oc * oc))
                    : ((4 - 2 * p[2] * oc + oc * oc) / (4 + 2 * p[2] * oc + oc * oc));

                b0[0] = ishpass ? (oc * oc / (c1 * c1 + c1 * p[0] * oc + oc * oc)) : (oc * oc / (4 + 2 * p[0] * oc + oc * oc));
                b0[1] = ishpass ? (-2 * b0[0]) : (2 * b0[0]);
                b0[2] = ishpass ? b0[0] : b0[0];

                b1[0] = ishpass ? (oc * oc / (c1 * c1 + c1 * p[1] * oc + oc * oc)) : (oc * oc / (4 + 2 * p[1] * oc + oc * oc));
                b1[1] = ishpass ? (-2 * b1[0]) : (2 * b1[0]);
                b1[2] = ishpass ? b1[0] : b1[0];

                b2[0] = ishpass ? (oc * oc / (c1 * c1 + c1 * p[2] * oc + oc * oc)) : (oc * oc / (4 + 2 * p[2] * oc + oc * oc));
                b2[1] = ishpass ? (-2 * b2[0]) : (2 * b2[0]);
                b2[2] = ishpass ? b2[0] : b2[0];

                this._mk(a0, b0, one_0, false);
                this._mk(a1, b1, one_1, false);
                this._mk(a2, b2, one_2, false);
                array = iszero
                    ? this._getArray(array.length)
                    : array.map((_, i) => one_0[i] + one_1[i] + one_2[i]);
                break;

            case 10: // BS-48
                p[0] = ishpass ? 1.81936630933058 : 1.81936630933058;
                p[1] = ishpass ? 1.69465016047187 : 1.69465016047187;
                p[2] = ishpass ? 1.42227636169708 : 1.42227636169708;
                p[3] = ishpass ? 0.92434808250642 : 0.92434808250642;

                a0[0] = ishpass ? 1 : 1;
                a0[1] = ishpass
                    ? (-2 * (oc * oc - c1 * c1) / (c1 * c1 + c1 * p[0] * oc + oc * oc))
                    : (2 * (oc * oc - 4) / (4 + 2 * p[0] * oc + oc * oc));
                a0[2] = ishpass
                    ? ((c1 * c1 - c1 * p[0] * oc + oc * oc) / (c1 * c1 + c1 * p[0] * oc + oc * oc))
                    : ((4 - 2 * p[0] * oc + oc * oc) / (4 + 2 * p[0] * oc + oc * oc));

                a1[0] = ishpass ? 1 : 1;
                a1[1] = ishpass
                    ? (-2 * (oc * oc - c1 * c1) / (c1 * c1 + c1 * p[1] * oc + oc * oc))
                    : (2 * (oc * oc - 4) / (4 + 2 * p[1] * oc + oc * oc));
                a1[2] = ishpass
                    ? ((c1 * c1 - c1 * p[1] * oc + oc * oc) / (c1 * c1 + c1 * p[1] * oc + oc * oc))
                    : ((4 - 2 * p[1] * oc + oc * oc) / (4 + 2 * p[1] * oc + oc * oc));

                a2[0] = ishpass ? 1 : 1;
                a2[1] = ishpass
                    ? (-2 * (oc * oc - c1 * c1) / (c1 * c1 + c1 * p[2] * oc + oc * oc))
                    : (2 * (oc * oc - 4) / (4 + 2 * p[2] * oc + oc * oc));
                a2[2] = ishpass
                    ? ((c1 * c1 - c1 * p[2] * oc + oc * oc) / (c1 * c1 + c1 * p[2] * oc + oc * oc))
                    : ((4 - 2 * p[2] * oc + oc * oc) / (4 + 2 * p[2] * oc + oc * oc));

                a3[0] = ishpass ? 1 : 1;
                a3[1] = ishpass
                    ? (-2 * (oc * oc - c1 * c1) / (c1 * c1 + c1 * p[3] * oc + oc * oc))
                    : (2 * (oc * oc - 4) / (4 + 2 * p[3] * oc + oc * oc));
                a3[2] = ishpass
                    ? ((c1 * c1 - c1 * p[3] * oc + oc * oc) / (c1 * c1 + c1 * p[3] * oc + oc * oc))
                    : ((4 - 2 * p[3] * oc + oc * oc) / (4 + 2 * p[3] * oc + oc * oc));

                b0[0] = ishpass ? (oc * oc / (c1 * c1 + c1 * p[0] * oc + oc * oc)) : (oc * oc / (4 + 2 * p[0] * oc + oc * oc));
                b0[1] = ishpass ? (-2 * b0[0]) : (2 * b0[0]);
                b0[2] = ishpass ? b0[0] : b0[0];

                b1[0] = ishpass ? (oc * oc / (c1 * c1 + c1 * p[1] * oc + oc * oc)) : (oc * oc / (4 + 2 * p[1] * oc + oc * oc));
                b1[1] = ishpass ? (-2 * b1[0]) : (2 * b1[0]);
                b1[2] = ishpass ? b1[0] : b1[0];

                b2[0] = ishpass ? (oc * oc / (c1 * c1 + c1 * p[2] * oc + oc * oc)) : (oc * oc / (4 + 2 * p[2] * oc + oc * oc));
                b2[1] = ishpass ? (-2 * b2[0]) : (2 * b2[0]);
                b2[2] = ishpass ? b2[0] : b2[0];

                b3[0] = ishpass ? (oc * oc / (c1 * c1 + c1 * p[3] * oc + oc * oc)) : (oc * oc / (4 + 2 * p[3] * oc + oc * oc));
                b3[1] = ishpass ? (-2 * b3[0]) : (2 * b3[0]);
                b3[2] = ishpass ? b3[0] : b3[0];

                this._mk(a0, b0, one_0, false);
                this._mk(a1, b1, one_1, false);
                this._mk(a2, b2, one_2, false);
                this._mk(a3, b3, one_3, false);
                array = iszero
                    ? this._getArray(array.length)
                    : array.map((_, i) => one_0[i] + one_1[i] + one_2[i] + one_3[i]);
                break;

            case 11: // LK-12
                a0[0] = ishpass ? 1 : 1;
                a0[1] = ishpass ? (-(oc - c1) / (c1 + oc)) : ((oc - 2) / (2 + oc));
                a0[2] = ishpass ? 0 : 0;

                a1[0] = ishpass ? a0[0] : a0[0];
                a1[1] = ishpass ? a0[1] : a0[1];
                a1[2] = ishpass ? a0[2] : a0[2];

                b0[0] = ishpass ? (oc / (c1 + oc)) : (oc / (2 + oc));
                b0[1] = ishpass ? (-b0[0]) : b0[0];
                b0[2] = ishpass ? 0 : 0;

                b1[0] = ishpass ? b0[0] : b0[0];
                b1[1] = ishpass ? b0[1] : b0[1];
                b1[2] = ishpass ? b0[2] : b0[2];

                this._mk(a0, b0, one_0, false);
                this._mk(a1, b1, one_1, false);
                array = iszero ? this._getArray(array.length) : array.map((_, i) => one_0[i] + one_1[i]);
                break;

            case 12: // LK-24
                p[0] = ishpass ? 1.41421356237309 : 1.41421356237309;

                a0[0] = ishpass ? 1 : 1;
                a0[1] = ishpass
                    ? (-2 * (oc * oc - c1 * c1) / (c1 * c1 + c1 * p[0] * oc + oc * oc))
                    : (2 * (oc * oc - 4) / (4 + 2 * p[0] * oc + oc * oc));
                a0[2] = ishpass
                    ? ((c1 * c1 - c1 * p[0] * oc + oc * oc) / (c1 * c1 + c1 * p[0] * oc + oc * oc))
                    : ((4 - 2 * p[0] * oc + oc * oc) / (4 + 2 * p[0] * oc + oc * oc));

                a1[0] = ishpass ? a0[0] : a0[0];
                a1[1] = ishpass ? a0[1] : a0[1];
                a1[2] = ishpass ? a0[2] : a0[2];

                b0[0] = ishpass ? (oc * oc / (c1 * c1 + c1 * p[0] * oc + oc * oc)) : (oc * oc / (4 + 2 * p[0] * oc + oc * oc));
                b0[1] = ishpass ? (-2 * b0[0]) : (2 * b0[0]);
                b0[2] = ishpass ? b0[0] : b0[0];

                b1[0] = ishpass ? b0[0] : b0[0];
                b1[1] = ishpass ? b0[1] : b0[1];
                b1[2] = ishpass ? b0[2] : b0[2];

                this._mk(a0, b0, one_0, false);
                this._mk(a1, b1, one_1, false);
                array = iszero ? this._getArray(array.length) : array.map((_, i) => one_0[i] + one_1[i]);
                break;
            case 13: // LK-36
                p[0] = ishpass ? 0.76536686473018 : 0.76536686473018;
                p[1] = ishpass ? 1.84775906502257 : 1.84775906502257;
                p[2] = ishpass ? 1.41421356237309 : 1.41421356237309;

                a0[0] = ishpass ? 1 : 1;
                a0[1] = ishpass
                    ? (-2 * (oc * oc - c1 * c1) / (c1 * c1 + c1 * p[0] * oc + oc * oc))
                    : (2 * (oc * oc - 4) / (4 + 2 * p[0] * oc + oc * oc));
                a0[2] = ishpass
                    ? ((c1 * c1 - c1 * p[0] * oc + oc * oc) / (c1 * c1 + c1 * p[0] * oc + oc * oc))
                    : ((4 - 2 * p[0] * oc + oc * oc) / (4 + 2 * p[0] * oc + oc * oc));

                a1[0] = ishpass ? 1 : 1;
                a1[1] = ishpass
                    ? (-2 * (oc * oc - c1 * c1) / (c1 * c1 + c1 * p[1] * oc + oc * oc))
                    : (2 * (oc * oc - 4) / (4 + 2 * p[1] * oc + oc * oc));
                a1[2] = ishpass
                    ? ((c1 * c1 - c1 * p[1] * oc + oc * oc) / (c1 * c1 + c1 * p[1] * oc + oc * oc))
                    : ((4 - 2 * p[1] * oc + oc * oc) / (4 + 2 * p[1] * oc + oc * oc));

                a2[0] = ishpass ? 1 : 1;
                a2[1] = ishpass
                    ? (-2 * (oc * oc - c1 * c1) / (c1 * c1 + c1 * p[2] * oc + oc * oc))
                    : (2 * (oc * oc - 4) / (4 + 2 * p[2] * oc + oc * oc));
                a2[2] = ishpass
                    ? ((c1 * c1 - c1 * p[2] * oc + oc * oc) / (c1 * c1 + c1 * p[2] * oc + oc * oc))
                    : ((4 - 2 * p[2] * oc + oc * oc) / (4 + 2 * p[2] * oc + oc * oc));

                b0[0] = ishpass ? (oc * oc / (c1 * c1 + c1 * p[0] * oc + oc * oc)) : (oc * oc / (4 + 2 * p[0] * oc + oc * oc));
                b0[1] = ishpass ? (-2 * b0[0]) : (2 * b0[0]);
                b0[2] = ishpass ? b0[0] : b0[0];

                b1[0] = ishpass ? (oc * oc / (c1 * c1 + c1 * p[1] * oc + oc * oc)) : (oc * oc / (4 + 2 * p[1] * oc + oc * oc));
                b1[1] = ishpass ? (-2 * b1[0]) : (2 * b1[0]);
                b1[2] = ishpass ? b1[0] : b1[0];

                b2[0] = ishpass ? (oc * oc / (c1 * c1 + c1 * p[2] * oc + oc * oc)) : (oc * oc / (4 + 2 * p[2] * oc + oc * oc));
                b2[1] = ishpass ? (-2 * b2[0]) : (2 * b2[0]);
                b2[2] = ishpass ? b2[0] : b2[0];

                this._mk(a0, b0, one_0, false);
                this._mk(a1, b1, one_1, false);
                this._mk(a2, b2, one_2, false);
                array = iszero
                    ? this._getArray(array.length)
                    : array.map((_, i) => one_0[i] + one_1[i] + one_2[i]);
                break;

            case 14: // LK-48
                p[0] = ishpass ? 0.76536686473018 : 0.76536686473018;
                p[1] = ishpass ? 1.84775906502257 : 1.84775906502257;

                a0[0] = ishpass ? 1 : 1;
                a0[1] = ishpass
                    ? (-2 * (oc * oc - c1 * c1) / (c1 * c1 + c1 * p[0] * oc + oc * oc))
                    : (2 * (oc * oc - 4) / (4 + 2 * p[0] * oc + oc * oc));
                a0[2] = ishpass
                    ? ((c1 * c1 - c1 * p[0] * oc + oc * oc) / (c1 * c1 + c1 * p[0] * oc + oc * oc))
                    : ((4 - 2 * p[0] * oc + oc * oc) / (4 + 2 * p[0] * oc + oc * oc));

                a1[0] = ishpass ? 1 : 1;
                a1[1] = ishpass
                    ? (-2 * (oc * oc - c1 * c1) / (c1 * c1 + c1 * p[1] * oc + oc * oc))
                    : (2 * (oc * oc - 4) / (4 + 2 * p[1] * oc + oc * oc));
                a1[2] = ishpass
                    ? ((c1 * c1 - c1 * p[1] * oc + oc * oc) / (c1 * c1 + c1 * p[1] * oc + oc * oc))
                    : ((4 - 2 * p[1] * oc + oc * oc) / (4 + 2 * p[1] * oc + oc * oc));

                a2[0] = ishpass ? a0[0] : a0[0];
                a2[1] = ishpass ? a0[1] : a0[1];
                a2[2] = ishpass ? a0[2] : a0[2];

                a3[0] = ishpass ? a1[0] : a1[0];
                a3[1] = ishpass ? a1[1] : a1[1];
                a3[2] = ishpass ? a1[2] : a1[2];

                b0[0] = ishpass ? (oc * oc / (c1 * c1 + c1 * p[0] * oc + oc * oc)) : (oc * oc / (4 + 2 * p[0] * oc + oc * oc));
                b0[1] = ishpass ? (-2 * b0[0]) : (2 * b0[0]);
                b0[2] = ishpass ? b0[0] : b0[0];

                b1[0] = ishpass ? (oc * oc / (c1 * c1 + c1 * p[1] * oc + oc * oc)) : (oc * oc / (4 + 2 * p[1] * oc + oc * oc));
                b1[1] = ishpass ? (-2 * b1[0]) : (2 * b1[0]);
                b1[2] = ishpass ? b1[0] : b1[0];

                b2[0] = ishpass ? b0[0] : b0[0];
                b2[1] = ishpass ? b0[1] : b0[1];
                b2[2] = ishpass ? b0[2] : b0[2];

                b3[0] = ishpass ? b1[0] : b1[0];
                b3[1] = ishpass ? b1[1] : b1[1];
                b3[2] = ishpass ? b1[2] : b1[2];

                this._mk(a0, b0, one_0, false);
                this._mk(a1, b1, one_1, false);
                this._mk(a2, b2, one_2, false);
                this._mk(a3, b3, one_3, false);

                array = iszero
                    ? this._getArray(array.length)
                    : array.map((_, i) => one_0[i] + one_1[i] + one_2[i] + one_3[i]);
                break;
            default:
                break;
        }
        return array;
    }
}

export {
    EQUtil
};
